package com.test.service.impl;

import com.test.service.ExternalSystemService;
import com.test.service.MainService;
import com.test.service.ToDoService;
import com.test.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

@Service
public class MainServiceImpl implements MainService {

    private static final Logger LOGGER = LoggerFactory.getLogger(MainServiceImpl.class);
    public final ExecutorService executorService = Executors.newFixedThreadPool(10);

    @Resource
    private UserService userService;

    @Resource
    private ToDoService toDoService;

    @Resource
    private ExternalSystemService externalSystemService;

    @Override
    public String test1(final String userId) throws InterruptedException {

        return userService.queryUserInfo(userId) + ":"
               + toDoService.queryToDoInfo(userId) + ","
               + externalSystemService.queryToDoInfo(userId);
    }

    @Override
    public String test2(final String userId) throws InterruptedException, ExecutionException {
        final Future<String> userInfoFuture = executorService.submit(new CallQueryUserInfo(userId));
        final Future<String> todoInfoFuture = executorService.submit(new CallQueryTodoInfo(userId));
        final Future<String> externalSystemTodoInfoFuture = executorService.submit(new CallExternalSystemTodoInfo(userId));
        while (true) {
            if (userInfoFuture.isDone() && todoInfoFuture.isDone() && externalSystemTodoInfoFuture.isDone()) {
                return userInfoFuture.get() + ":"
                       + todoInfoFuture.get() + ","
                       + externalSystemTodoInfoFuture.get();
            }
        }
    }


    class CallQueryUserInfo implements Callable<String> {
        private final String userId;

        public CallQueryUserInfo(final String userId) {
            this.userId = userId;
        }

        @Override
        public String call() throws Exception {

            return userService.queryUserInfo(userId);
        }
    }

    class CallQueryTodoInfo implements Callable<String> {
        private final String userId;

        public CallQueryTodoInfo(final String userId) {
            this.userId = userId;
        }

        @Override
        public String call() throws Exception {

            return toDoService.queryToDoInfo(userId);
        }
    }

    class CallExternalSystemTodoInfo implements Callable<String> {
        private final String userId;

        public CallExternalSystemTodoInfo(final String userId) {
            this.userId = userId;
        }

        @Override
        public String call() throws Exception {

            return externalSystemService.queryToDoInfo(userId);
        }
    }


    @Override
    public String test3(final String userId) throws InterruptedException {
        final CountDownLatch latch = new CountDownLatch(3);
        final String [] results = new String[3];
        new Thread(() -> {
            try {
                results[0] = userService.queryUserInfo(userId);
            } catch (final InterruptedException e) {
                LOGGER.error("queryUserInfo error userId:{}", userId, e);
                Thread.currentThread().interrupt();
            } finally {
                latch.countDown();
            }
         }).start();

        new Thread(() -> {
            try {
                results[1] = toDoService.queryToDoInfo(userId);
            } catch (final InterruptedException e) {
                LOGGER.error("queryToDoInfo error userId:{}", userId, e);
                Thread.currentThread().interrupt();
            } finally {
                latch.countDown();
            }
        }).start();

        new Thread(() -> {
            try {
                results[2] = externalSystemService.queryToDoInfo(userId);
            } catch (final InterruptedException e) {
                LOGGER.error(" queryToDoInfo error userId:{}", userId, e);
                Thread.currentThread().interrupt();

            } finally {
                latch.countDown();
            }
        }).start();

        latch.await(); // 阻塞等待所有查询完成

        return results[0] + ":" + results[1] + "," + results[2];
    }

    @Override
    public String test4(final String userId) throws InterruptedException, ExecutionException {

        final CompletableFuture<String> userInfo = CompletableFuture.supplyAsync(() -> {
            try {
                return userService.queryUserInfo(userId);
            } catch (InterruptedException e) {
                LOGGER.error(" queryToDoInfo error userId:{}", userId, e);
                Thread.currentThread()
                    .interrupt();
                return null;
            }
        });

        final CompletableFuture<String> toDoInfo = CompletableFuture.supplyAsync(() -> {
            try {
                return toDoService.queryToDoInfo(userId);
            } catch (InterruptedException e) {
                LOGGER.error(" queryToDoInfo error userId:{}", userId, e);
                Thread.currentThread()
                    .interrupt();
                return null;
            }
        });

        final CompletableFuture<String> externalSystemTodoInfo = CompletableFuture.supplyAsync(() -> {
            try {
                return externalSystemService.queryToDoInfo(userId);
            } catch (InterruptedException e) {
                LOGGER.error(" queryToDoInfo error userId:{}", userId, e);
                Thread.currentThread()
                    .interrupt();
                return null;
            }
        });

        // 等待所有任务完成
        CompletableFuture.allOf(userInfo, toDoInfo, externalSystemTodoInfo).join();

        return userInfo.get() + ":" + toDoInfo.get() + "," + externalSystemTodoInfo.get();
    }

    @Override
    public String test5(final String userId) throws InterruptedException, ExecutionException {

        final CompletableFuture<String> userInfo = CompletableFuture.supplyAsync(() -> {
            try {
                return userService.queryUserInfo(userId);
            } catch (InterruptedException e) {
                LOGGER.error(" queryToDoInfo error userId:{}", userId, e);
                Thread.currentThread()
                    .interrupt();
                return null;
            }
        }, executorService);

        final CompletableFuture<String> toDoInfo = CompletableFuture.supplyAsync(() -> {
            try {
                return toDoService.queryToDoInfo(userId);
            } catch (InterruptedException e) {
                LOGGER.error(" queryToDoInfo error userId:{}", userId, e);
                Thread.currentThread()
                    .interrupt();
                return null;
            }
        }, executorService);

        final CompletableFuture<String> externalSystemTodoInfo = CompletableFuture.supplyAsync(() -> {
            try {
                return externalSystemService.queryToDoInfo(userId);
            } catch (InterruptedException e) {
                LOGGER.error(" queryToDoInfo error userId:{}", userId, e);
                Thread.currentThread()
                    .interrupt();
                return null;
            }
        }, executorService);

        // 等待所有任务完成
        CompletableFuture.allOf(userInfo, toDoInfo, externalSystemTodoInfo).join();

        return userInfo.get() + ":" + toDoInfo.get() + "," + externalSystemTodoInfo.get();
    }


}
